package net.sppan.blog.controller.offer;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ThreadLocalRandom;

import net.sppan.blog.bean.URLParam;
import net.sppan.blog.controller.BaseController;
import net.sppan.blog.model.Offer;
import net.sppan.blog.store.ConfigStore;
import net.sppan.blog.store.DeductionStore;
import net.sppan.blog.store.OfferStore;
import net.sppan.blog.store.UserStore;
import net.sppan.blog.utils.LocalCache;
import net.sppan.blog.utils.ObjectUtils;
import net.sppan.blog.utils.SimpleDateFormatUtil;

import org.apache.commons.lang.StringUtils;

import com.jfinal.log.Log;
import com.jfinal.plugin.redis.Redis;

public class OfferClickController extends BaseController {

	public static LocalCache<String, Integer> clickNumCache = new LocalCache<>("clickNumCache", 1000000);

	private static final Log logger = Log.getLog("OfferClickController");
	private static final Log logger1 = Log.getLog(OfferClickController.class);

	public void index() {
		String domain = ConfigStore.instance.getConfig().getDomainName();
		if (!domain.endsWith("/")) {
			domain += "/";
		}
		String path = getRequest().getContextPath();
		if (StringUtils.isNotBlank(path) && !path.endsWith("/")) {
			path += "/";
		}
		String errorPage = domain + path + "error.html";
		String offerId = getPara(URLParam.offerId.getCode());
		String userId = getPara(URLParam.userId.getCode());
		String parentId = getPara(URLParam.parentId.getCode());
		Map<String, String> paramMap = valuseMap();
		paramMap.put("p100", "0");//默认不扣量
		String status = "0";
		String clickUrl = "";
		try {
			//判断用户和offer的匹配关系
			List<String> ids = OfferStore.getInstance().getOfferIdss(parentId);
			if (ObjectUtils.isEmpty(ids)) {
				ids = new ArrayList<>();
			}
			List<String> allids = OfferStore.getInstance().getOfferIdss("all");
			if (ObjectUtils.isNotEmpty(allids)) {
				ids.addAll(allids);
			}
			if (ObjectUtils.isNotEmpty(ids) && ids.contains(offerId)) {
				//判断此offer是否扣量
				Integer ratio = DeductionStore.instance.getDeductRatio(offerId, parentId);
				if (ratio != null) {
					if (deduct(ratio)) {
						paramMap.put("p100", "1");
					}
				}
				Offer o = OfferStore.getInstance().getOfferById(offerId);
				if (o != null && StringUtils.isNotEmpty(o.getClickUrl()) && notLimitClick(paramMap)) {
					clickUrl = o.getClickUrl();
					status = "1";
					try {
						Date d = new Date();
						String offerKey = "offer_" + paramMap.get(URLParam.offerId.getCode());
						String userKey = "user_" + paramMap.get(URLParam.userId.getCode());
						String str = SimpleDateFormatUtil.format(d, SimpleDateFormatUtil.ymd) + " 23:59:59";
						int seconds = (int) ((SimpleDateFormatUtil.parse(str, SimpleDateFormatUtil.ymdhms).getTime() - d.getTime()) / 1000);
						synchronized (offerKey) {
							Integer num = Redis.use().get(offerKey);
							if (num == null) {
								Redis.use().setex(offerKey, seconds, 1);
							} else {
								int ttl = Redis.use().ttl(offerKey).intValue();
								Redis.use().setex(offerKey, ttl, num + 1);
							}
						}

						synchronized (userKey) {
							Integer num = Redis.use().get(userKey);
							if (num == null) {
								Redis.use().setex(userKey, seconds, 1);
							} else {
								int ttl = Redis.use().ttl(userKey).intValue();
								Redis.use().setex(userKey, ttl, num + 1);
							}
						}
						redirect(clickUrl);
					} catch (Exception e) {
						status = "0";
						logger1.error("跳转错误,click_url=" + clickUrl);
					}
					return;
				} else {
					redirect(errorPage);
				}
			} else {
				redirect(errorPage);
			}
		} catch (Exception e) {
			logger1.error("", e);
		} finally {
			printLog(paramMap, status, clickUrl);
		}

	}

	private boolean notLimitClick(Map<String, String> paramMap) {
		String userId = paramMap.get(URLParam.userId.getCode());
		String parentId = paramMap.get(URLParam.parentId.getCode());
		String offerId = paramMap.get(URLParam.offerId.getCode());
		String userKey = "user_" + userId;
		String offerKey = "offer_" + offerId;
		Integer userClick = Redis.use().get(userKey) == null ? 0 : Redis.use().get(userKey);
		Integer offerClick = Redis.use().get(offerKey) == null ? 0 : Redis.use().get(offerKey);
		Integer limit = UserStore.instance.getUserThreshold(parentId);
		Integer offerLimit = OfferStore.getInstance().getOfferById(offerId).getClickNumLimit();
		if (offerLimit == null) {
			offerLimit = Integer.MAX_VALUE;
		}

		if (limit > userClick && offerLimit > offerClick) {
			return true;
		}
		return false;
	}

	private void printLog(Map<String, String> paramMap, String status, String clickUrl) {
		String params = logStr(paramMap);
		String statusStr = "status=" + status;
		String tid = paramMap.get(URLParam.tid.getCode());
		String log = String.format("%s\t%s\t%s\t%s\t%s", System.currentTimeMillis(), statusStr, tid, params, clickUrl);
		logger.debug(log);
	}

	private String logStr(Map<String, String> paramMap) {
		StringBuilder sb = new StringBuilder();
		for (Entry<String, String> e : paramMap.entrySet()) {
			sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
		}
		String s = sb.toString();
		if (s.endsWith("&")) {
			s = s.substring(0, s.length() - 1);
		}
		return s;
	}

	private boolean deduct(Integer ratio) {
		Integer magic = ThreadLocalRandom.current().nextInt(100);
		if (ratio > magic) {
			return true;
		}
		return false;
	}

	private Map<String, String> valuseMap() {
		Map<String, String> map = new LinkedHashMap<>();
		for (URLParam param : URLParam.values()) {
			String k = param.getCode();
			String v = getPara(k);
			map.put(k, v);
		}
		return map;
	}

}
